`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: 
// Engineer: 
// 
// Create Date: 2017/10/23 15:21:30
// Design Name: 
// Module Name: maindec
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//////////////////////////////////////////////////////////////////////////////////
import structs::*;
`include "op.vh"
`include "funct.vh"

module maindec(
	input wire[5:0] op, funct,
    input wire [31:0] instr,
    output control_sign_t controlsign
    );
    wire [4:0] rt;
    wire [4:0] rd;
    wire [4:0] rs;
    assign rt = instr[20:16];
    assign rd = instr[15:11];
    assign rs =instr[25:21];
    assign controlsign.regwrite = (op == `SPECIAL_OP && 
                                                      funct != `FUNCT_MTHI  && funct != `FUNCT_MTLO &&
                                                      funct != `FUNCT_MULT && funct != `FUNCT_MULTU && 
                                                      funct != `FUNCT_DIV && funct != `FUNCT_DIVU && funct != `FUNCT_JR) ||
                                                      (op == `OP_ANDI) ||
                                                      (op == `OP_XORI) ||
                                                      (op == `OP_ORI) ||
                                                      (op == `OP_LUI) ||
                                                      (op == `OP_ADDI) ||
                                                      (op == `OP_ADDIU) ||
                                                      (op == `OP_SLTI) ||
                                                      (op == `OP_SLTIU) ||
                                                      (op == `OP_JAL) ||
                                                      (op == `OP_BLTZAL && rt == 5'b10000) ||
                                                      (op == `OP_BGEZAL && rt ==5'b10001) ||
                                                      (op == `OP_LB) ||
                                                      (op == `OP_LBU) ||
                                                      (op == `OP_LH) ||
                                                      (op == `OP_LHU) ||
                                                      (op == `OP_LW) ||
                                                      (funct== `FUNCT_SLL && op==`OP_SLL)||
                                                      (funct== `FUNCT_SRL && op==`OP_SRL)||
                                                      (funct== `FUNCT_SRA && op==`OP_SRA)||
                                                      (funct== `FUNCT_SLLV && op==`OP_SLLV)||
                                                      (funct== `FUNCT_SRLV && op==`OP_SRLV)||
                                                      (funct== `FUNCT_SRAV && op==`OP_SRAV)||
                                                      (op == `OP_MFC0 && rs == 5'b000000);
                                                      
assign controlsign.regdst = (op == `SPECIAL_OP) || 
                            (op == 6'b111111 && funct == 6'b000000) ||
                            (op == `OP_SB) ||
                            (op == `OP_SH) ||
                            (op == `OP_SW);
                            

assign controlsign.alusrc = (op == `OP_ANDI) ||
                                             (op == `OP_XORI) || 
                                             (op == `OP_LUI) || 
                                             (op == `OP_ORI) || 
                                             (op == `OP_ADDI) || 
                                             (op == `OP_ADDIU) || 
                                             (op == `OP_SLTI) || 
                                             (op == `OP_SLTIU) || 
                                             (op == `OP_LB) || 
                                             (op == `OP_LBU) || 
                                             (op == `OP_LH) || 
                                             (op == `OP_LHU) || 
                                             (op == `OP_LW) || 
                                             (op == `OP_SB) || 
                                             (op == `OP_SH) || 
                                             (op == `OP_SW);
                                             
assign controlsign.branch = (op == `OP_BEQ) ||
                                              (op == `OP_BNE) ||
                                              (op == `OP_BLEZ) ||
                                              (op == `OP_BGTZ) ||
                                              
                                              (op == 6'b000001 && rt == 5'b00000) ||
                                              (op == 6'b000001 && rt == 5'b10000) ||
                                              (op == 6'b000001 && rt == 5'b00001) ||
                                              (op == 6'b000001 && rt == 5'b10001);
                                              
assign controlsign.memwrite = (op == `OP_SB) || (op == `OP_SH) || (op == `OP_SW);

assign controlsign.memtoreg = (op == `OP_LB) || 
                                                    (op == `OP_LBU) || 
                                                    (op == `OP_LH) || 
                                                    (op == `OP_LHU) ||
                                                    (op == `OP_LW);
                                                    
assign controlsign.jump = (op == `OP_J) ||
                                           (op == `OP_JAL);

assign controlsign.lordD = (op==`OP_LB)?`Sign_LB:
                            (op==`OP_LBU)?`Sign_LBU:
                            (op==`OP_LH)?`Sign_LH:
                            (op==`OP_LHU)?`Sign_LHU:
                            (op==`OP_LW)?`Sign_LW:
                              3'b000;
assign controlsign.storeD = (op==`OP_SB)?`Sign_SB:
                            (op==`OP_SH)?`Sign_SH:
                            (op==`OP_SW)?`Sign_SW:
                            3'b000;

assign controlsign.cmpcontrol = (op == `OP_BEQ) ? `Sign_EQ :
                                                      (op == `OP_BNE) ? `Sign_NE :
                                                      (op == `OP_BGTZ) ? `Sign_GZ :
                                                      ( (op == `OP_BGEZ && rt == 5'b00001) || (op == `OP_BGEZAL && rt == 5'b10001)) ? `Sign_GEZ :
                                                      ( (op == `OP_BLTZ && rt == 5'b00000) || (op == `OP_BLTZAL && rt == 5'b10000) ) ? `Sign_LZ : 
                                                      (op == `OP_BLEZ) ? `Sign_LEZ:
                                                      3'b000;
                                                    
assign controlsign.jumpreg = (op == `SPECIAL_OP && funct == `FUNCT_JR) ||
                                                 (op == `SPECIAL_OP  && funct == `FUNCT_JALR);
                                                 
assign controlsign.jumplink = (op == `OP_JAL)||
                                                 (op == `SPECIAL_OP  && funct == `FUNCT_JALR)||
                                                 (op == `OP_BGEZAL && rt == 5'b10001)||
                                                 (op == `OP_BLTZAL && rt == 5'b10000);

// JALR has 2 fomats,JALR rd, rs; another is JALR rs, the write reg of which is r31 defaultly
assign controlsign.jumplinkreg = (op == `SPECIAL_OP  && funct == `FUNCT_JALR && rd != 5'b00000);

// cp0 write
assign controlsign.cp0we = (op == `OP_MTC0 && rs == 5'b00100);

// cp read
assign controlsign.cp0read = (op == `OP_MFC0 && rs == 5'b000000);
// invalid all instr
assign controlsign.invalid = ~((op == `SPECIAL_OP && (funct== `FUNCT_AND||
funct== `FUNCT_OR ||funct== `FUNCT_XOR ||funct== `FUNCT_NOR ||funct== `FUNCT_SLL ||funct== `FUNCT_SRL ||funct== `FUNCT_SRA ||funct== `FUNCT_SLLV ||
funct== `FUNCT_SRLV ||funct== `FUNCT_SRAV ||funct== `FUNCT_MFHI ||funct== `FUNCT_MFLO ||funct== `FUNCT_MTHI ||funct== `FUNCT_MTLO ||funct== `FUNCT_ADD ||
funct== `FUNCT_ADDU ||funct== `FUNCT_SUB ||funct== `FUNCT_SUBU ||funct== `FUNCT_SLT ||funct== `FUNCT_SLTU ||funct== `FUNCT_MULT ||funct== `FUNCT_MULTU ||
funct== `FUNCT_DIV ||funct== `FUNCT_DIVU ||funct== `FUNCT_JR ||funct== `FUNCT_JALR ||funct==6'b 001101||funct== 6'b001100))
||(op == `OP_ANDI)
||(op == `OP_XORI)
||(op == `OP_LUI)
||(op == `OP_ORI)
||(op == `OP_ADDI)
||(op == `OP_ADDIU)
||(op == `OP_SLTI)
||(op == `OP_SLTIU)
||(op == `OP_J)
||(op == `OP_JAL)
||(op == `OP_BEQ)
||(op == `OP_BGTZ && instr[20:16]==5'b00000)
||(op == `OP_BLEZ && instr[20:16]==5'b00000)
||(op == `OP_BNE )
||(op == `OP_BLTZ && instr[20:16]==5'b00000)
||(op == `OP_BLTZAL && instr[20:16]== 5'b10000)
||(op == `OP_BGEZ && instr[20:16]== 5'b00001)
||(op == `OP_BGEZAL && instr[20:16]== 5'b10001)
||(op == `OP_LB)
||(op == `OP_LBU)
||(op == `OP_LH)
||(op == `OP_LHU)
||(op == `OP_LW)
||(op == `OP_SB)
||(op == `OP_SH)
||(op == `OP_SW)
||(op == `OP_MTC0 && instr[25:21]==5'b00100)
||(op == `OP_MFC0 && instr[25:21]==5'b00000)
||(instr == 32'b010000_1_0000_0000_0000_0000_000_011000)
);
assign controlsign.breakpoint = (op==`SPECIAL_OP && funct == 6'b001101);
assign controlsign.syscall = (op==`SPECIAL_OP && funct == 6'b001100);
assign controlsign.eret = (instr == 32'b010000_1_0000_0000_0000_0000_000_011000);
endmodule
